package com.wigball.java.jchef.parser;

import java.io.File;
import java.util.List;

import org.apache.commons.io.FileUtils;

import com.wigball.java.jchef.model.common.methods.MethodFactory;
import com.wigball.java.jchef.model.ingredients.IngredientFactory;
import com.wigball.java.jchef.script.ChefScript;
import com.wigball.java.jchef.util.StringNormalizer;

public final class Parser {

	private static final Parser INSTANCE = new Parser();
	
	public static Parser getInstance() {
		return INSTANCE;
	}
	
	private Parser() {
		
	}
	
	/**
	 * May throw ArrayIndexOutOfBoundsException while parsing
	 * @param f
	 * @return
	 * @throws ParserException
	 */
	public ChefScript parse(File f) {
		if (f == null) {
			throw new ParserException("File must not be null");
		}
		
		try {
			List<String> fileLines = FileUtils.readLines(f);
			List<String> codeLines = StringNormalizer.normalize(fileLines);
			
			ChefScript script = new ChefScript();
			
			int lineCounter = 0;
			
			// TITLE
			ParserState state = ParserState.TITLE;
			script.setTitle(codeLines.get(lineCounter++));
			
			// REST
			state = ParserState.COMMENTS;
			
			StringBuffer comments = new StringBuffer();
			StringBuffer methods = new StringBuffer();
			
			for (; lineCounter < codeLines.size(); lineCounter++) {
				String line = codeLines.get(lineCounter);
				
				if ("Ingredients.".equals(line)) {
					state = ParserState.INGREDIENTS;
					continue;
				}
				else if (line.startsWith("Cooking time:")) {
					state = ParserState.COOKING_TIME;
					script.setCookingTime(line);
					continue;
				}
				else if (line.startsWith("Pre-heat oven to")) {
					state = ParserState.OVEN_TEMPERATURE;
					script.setOvenTemperature(line);
					continue;
				}
				else if ("Method.".equals(line)) {
					state = ParserState.METHOD;
					continue;
				}
				else if (line.startsWith("Serves")) {
					state = ParserState.SERVES;
					// TODO read value
					continue;
				}
				else {
					if (state == ParserState.COMMENTS) {
						if (comments.length() > 0) {
							comments.append(' ');
						}
						
						comments.append(line);
						continue;
					}
					else if (state == ParserState.INGREDIENTS) {
						script.addIngredient(IngredientFactory.fromString(line));
						continue;
					}
					else if (state == ParserState.METHOD) {
						if (methods.length() > 0) {
							methods.append(' ');
						}
						
						methods.append(line);
						
						continue;
					}
				}
			}
			
			script.setComments(comments.toString());
			
			String[] allMethods = methods.toString().split("\\.");
			List<String> normalizedMethods = StringNormalizer.normalize(allMethods);
			
			for (String method : normalizedMethods) {
				script.addMethod(MethodFactory.fromString(method));
			}
			
			return script;
		} catch (Exception e) {
			throw new ParserException(e);
		}
	}
	
}
